﻿// <copyright file="BlogGenericRepository.cs" company="Clever Software">
// Copyright (c) 2013, 2014 All Right Reserved, http://www.cleversoftware.by
//
// This source is subject to the Microsoft Permissive License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Clever Software</author>
// <email>info@cleversoftware.by</email>
// <date>2014-02-04</date> 
// <summary>CleverCMS source code</summary>

namespace CleverCMS.Blog.Data
{

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data;
    using System.Linq.Expressions;
    using System.Data.Entity;
    using System.Diagnostics;

    public class BlogGenericRepository<TEntity> : IBlogGenericRepository<TEntity> where TEntity : class
    {
        internal BlogDataContext context;
        internal DbSet<TEntity> dbSet;
        
        public BlogGenericRepository(BlogDataContext ctx)
        {
            this.context = ctx;
            this.dbSet = context.Set<TEntity>();
        }
        
        /// <summary>
        /// Load all entities of T filtered
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="orderBy"></param>
        /// <param name="includeProperties"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> LoadAll(Expression<Func<TEntity, bool>> filter = null,  Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
                query = query.Where(filter);

            foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                query = query.Include(includeProperty);

            if (orderBy != null)
                return orderBy(query);
            else
                return query;
        }
        
        /// <summary>
        /// Load all entities of T 
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<TEntity> LoadAll() 
        {
            IQueryable<TEntity> query = dbSet;
            return query;
        }

        //TODO: WTF ??? :)
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual int Count()
        {
            return dbSet.Count();
        }
        
        /// <summary>
        /// Load entity of T
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// 
        public virtual TEntity Load(object id)
        {
            return dbSet.Find(id);
        }
        
        /// <summary>
        /// Save entity of T
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isNew"></param>
        public virtual void Save(TEntity entity, bool isNew)
        {
            if (isNew)
                dbSet.Add(entity);
            else
                if (context.Entry(entity).State == EntityState.Detached)
                {
                    dbSet.Attach(entity);
                    context.Entry(entity).State = EntityState.Modified;
                }

            context.SaveChanges();

        }

        /// <summary>
        /// Delete entity of T by Id
        /// </summary>
        /// <param name="id"></param>
        public virtual void Delete(object id)
        {
            TEntity entityToDelete = dbSet.Find(id);
            Delete(entityToDelete);
        }

        /// <summary>
        /// Delete entity of T by instance
       /// </summary>
       /// <param name="entityToDelete"></param>
        public virtual void Delete(TEntity entityToDelete)
        {
            if (context.Entry(entityToDelete).State == EntityState.Detached)
                dbSet.Attach(entityToDelete);

            dbSet.Remove(entityToDelete);
            context.SaveChanges();
        }

        /// <summary>
        /// Get collection of T by raw SQL query
        /// </summary>
        /// <param name="query"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
        {
            return dbSet.SqlQuery(query, parameters).ToList();
        }

        /// <summary>
        /// Add entity to context
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Add(TEntity entity) 
        {
            context.Set<TEntity>().Add(entity);
        }
        
        /// <summary>
        /// Save context
        /// </summary>
        public virtual void Save()
        {
            context.SaveChanges();
        }
    }

}